import numpy as np
import json
from Object_for_FJSP import Job_Object,Machine_Object
from Instance_Generator import product_classdicts,product_crafts,Device_list,all_productins_types
import pandas as pd
import datetime

class Situation:
    def __init__(self,bom_dicts, J_num, order_data, Job_passtime_matrixs,Job_opnum_lst):
        self.bom_dicts = bom_dicts
        self.J_num = J_num
        self.order_data = order_data
        self.Job_passtime_matrixs = Job_passtime_matrixs
        self.Jobop_passtime_matrixs = [arr01.max(axis=0) for arr01 in Job_passtime_matrixs]
        self.today_str = None
        self.today_timestamp = None
        self.J = Job_opnum_lst
        self.O_num = sum(Job_opnum_lst)

        self.product_classdicts = product_classdicts
        self.product_crafts  = product_crafts
        self.all_productins_types  = all_productins_types
        self.productins_nums  = len(all_productins_types)
        self.Device_list  = Device_list
        self.M_num = len(Device_list)

        Switch_df = pd.read_excel('./data/设备换型.xlsx')
        Switch_dicts = {}
        for name, group in Switch_df.groupby(['车间','机台','切换类型']):
            assert len(group) == 1
            Switch_dicts['_'.join(name)] = float(group['换型时间(h)'].iloc[0])*60
        self.Switch_dicts  = Switch_dicts

        ######################### 动态变量 ######################################
        self.CTK=[0 for _ in range(self.M_num)]      #各机器上最后一道工序的完工时间
        self.UK=[0 for _ in range(self.M_num)]       #各机器的实际使用率
        self.OP=[0 for _ in range(self.J_num)]       #各工件的已加工工序数
        self.CRJ=[0 for _ in range(self.J_num)]      #工件完工率
        # 工件集：
        self.Jobs=[]
        for i in range(self.J_num):
            F=Job_Object(i)
            self.Jobs.append(F)
        #机器集
        self.Machines = []
        for i in range(self.M_num):
            F = Machine_Object(i)
            self.Machines.append(F)

    #更新数据
    def _Update(self,Job,Machine):
        self.CTK[Machine]=max(self.Machines[Machine].End)
        self.OP[Job]+=1
        self.UK[Machine]=sum(self.Machines[Machine].T)/self.CTK[Machine]
        self.CRJ[Job]=self.OP[Job]/self.J[Job]
        assert self.CRJ[Job] <= 1

    # Composite dispatching rule 2
    # return Job,Machine
    def rule(self):
        # T_cur:平均完工时间
        tar_jobs = [i for i in range(self.J_num) if self.CRJ[i] < 1]
        tar_jobs_residue = []
        for i in tar_jobs:
            jiaofu_t = datetime.datetime.strptime(self.order_data[i]['交付日期'], '%Y-%m-%d %H:%M:%S').timestamp()-self.today_timestamp
            jiaofu_t = jiaofu_t/60
            devices_temp = self.Job_passtime_matrixs[i][:,self.OP[i]].nonzero()[0]
            duans_time = np.mean([self.CTK[k] for k in devices_temp])
            time_fenzhong = 0
            for j in range(self.OP[i],self.J[i]):
                time_fen = (int(self.order_data[i]['数量']) * 100) / float(self.Jobop_passtime_matrixs[i][j])
                time_fenzhong += time_fen
            tar_jobs_residue.append(jiaofu_t-(duans_time+time_fenzhong))

        assert len(tar_jobs_residue) == len(tar_jobs)
        yanqi_jobs =              [tar_jobs[xi] for xi in range(len(tar_jobs)) if tar_jobs_residue[xi] < 0]
        yanqi_reside =    [tar_jobs_residue[xi] for xi in range(len(tar_jobs)) if tar_jobs_residue[xi] < 0]
        notyanqi_jobs =          [tar_jobs[xi] for xi in range(len(tar_jobs)) if tar_jobs_residue[xi] >= 0]
        notyanqi_reside = [tar_jobs_residue[xi] for xi in range(len(tar_jobs)) if tar_jobs_residue[xi] >= 0]

        if len(yanqi_jobs) == 0:
            huanxing_yes = []
            for i in notyanqi_jobs:
                jobi_info = self.order_data[i]
                jobgg = eval(jobi_info['产品名称'])[3].split('×')[-1]
                jobys = eval(jobi_info['产品名称'])[1].split('-')[-1]
                jobys_lst = [ys for ys in jobys if ys in ['红', '蓝', '绿', '黄', '黑', '白']]
                devices_temp = self.Job_passtime_matrixs[i][:, self.OP[i]].nonzero()[0]
                currt_xinhao_lst = []
                for m in devices_temp:
                    Machine_name = self.Device_list[m]
                    if len(self.Machines[m].assign_for) > 0:
                        currt_xinhao01 = 1
                        currt_xinhao02 = 1
                        joi_ino = self.order_data[self.Machines[m].assign_for[-1][0]]
                        mmgg = eval(joi_ino['产品名称'])[3].split('×')[-1]
                        mmys = eval(joi_ino['产品名称'])[1].split('-')[-1]
                        ys_lst = [ys for ys in mmys if ys in ['红', '蓝', '绿', '黄', '黑', '白']]
                        if len(jobgg) > 0 and len(mmgg) > 0 and jobgg != mmgg:
                            device_index = Machine_name + '_规格切换'
                            if device_index in self.Switch_dicts.keys():
                                pass
                            else:
                                currt_xinhao01 = 0
                        else:
                            currt_xinhao01 = 0
                        if len(jobys_lst) > 0 and len(ys_lst) > 0 and ''.join(jobys_lst) != ''.join(ys_lst):
                            color_index = Machine_name + '_颜色切换'
                            if color_index in self.Switch_dicts.keys():
                                pass
                            else:
                                currt_xinhao02 = 0
                        else:
                            currt_xinhao02 = 0
                        if (currt_xinhao02+currt_xinhao01) == 0:
                            currt_xinhao = 0
                        else:
                            currt_xinhao = 1
                    else:
                        currt_xinhao = 0
                    currt_xinhao_lst.append(currt_xinhao)
                if sum(currt_xinhao_lst) < len(currt_xinhao_lst):
                    huanxing_yes.append(0)
                else:
                    huanxing_yes.append(1)
            no_huanxings = [hi for hi in range(len(huanxing_yes)) if huanxing_yes[hi] == 0]
            if len(no_huanxings ) == 0:
                ind_ch = np.argmin(notyanqi_reside)
                job_ids = notyanqi_jobs[ind_ch]
            else:
                no_huanxings_reside = [notyanqi_reside[hi] for hi in no_huanxings]
                ind_ch = np.argmin(no_huanxings_reside)
                ind_ids = no_huanxings[ind_ch]
                job_ids = notyanqi_jobs[ind_ids]
        else:
            ind_ch = np.argmin(yanqi_reside)
            job_ids = yanqi_jobs[ind_ch]

        devices_temp = self.Job_passtime_matrixs[job_ids][:, self.OP[job_ids]].nonzero()[0]
        jobi_info = self.order_data[job_ids]
        jobgg = eval(jobi_info['产品名称'])[3].split('×')[-1]
        jobys = eval(jobi_info['产品名称'])[1].split('-')[-1]
        jobys_lst = [ys for ys in jobys if ys in ['红', '蓝', '绿', '黄', '黑', '白']]
        tar_machine_lst = []
        for m in devices_temp:
            Machine_name = self.Device_list[m]
            if len(self.Machines[m].assign_for) > 0:
                currt_xinhao01 = 1
                currt_xinhao02 = 1
                joi_ino = self.order_data[self.Machines[m].assign_for[-1][0]]
                mmgg = eval(joi_ino['产品名称'])[3].split('×')[-1]
                mmys = eval(joi_ino['产品名称'])[1].split('-')[-1]
                ys_lst = [ys for ys in mmys if ys in ['红', '蓝', '绿', '黄', '黑', '白']]
                if len(jobgg) > 0 and len(mmgg) > 0 and jobgg != mmgg:
                    device_index = Machine_name + '_规格切换'
                    if device_index in self.Switch_dicts.keys():
                        pass
                    else:
                        currt_xinhao01 = 0
                else:
                    currt_xinhao01 = 0
                if len(jobys_lst) > 0 and len(ys_lst) > 0 and ''.join(jobys_lst) != ''.join(ys_lst):
                    color_index = Machine_name + '_颜色切换'
                    if color_index in self.Switch_dicts.keys():
                        pass
                    else:
                        currt_xinhao02 = 0
                else:
                    currt_xinhao02 = 0
                if (currt_xinhao02 + currt_xinhao01) == 0:
                    currt_xinhao = 0
                else:
                    currt_xinhao = 1
            else:
                currt_xinhao = 0
            tar_machine_lst.append(currt_xinhao)
        # no_huanxings = [hi for hi in range(len(tar_machine_lst)) if tar_machine_lst[hi] == 0]
        device_no_huanxings = [devices_temp[hi] for hi in range(len(tar_machine_lst)) if tar_machine_lst[hi] == 0]
        if len(device_no_huanxings) > 0:
            nonzeroes_ctk = [self.CTK[mid] for mid in device_no_huanxings]
            ctk_id = np.argmin(nonzeroes_ctk)
            tar_machine = int(device_no_huanxings[ctk_id])
        else:
            nonzeroes_ctk = [self.CTK[mid] for mid in devices_temp]
            ctk_id = np.argmin(nonzeroes_ctk)
            tar_machine = int(devices_temp[ctk_id])
        tar_op = self.OP[job_ids]
        return (job_ids,tar_op),tar_machine

    def scheduling(self,action):
        Job_i,Machine = action[0],action[1]

        Machine_name = self.Device_list[Machine]
        jobi_info = self.order_data[Job_i[0]]
        jobgg = eval(jobi_info['产品名称'])[3].split('×')[-1]
        jobys = eval(jobi_info['产品名称'])[1].split('-')[-1]
        jobys_lst = [ys for ys in jobys if ys in ['红','蓝','绿','黄','黑','白']]
        gg_ind = 0
        ys_ind = 0
        if len(self.Machines[Machine].assign_for) > 0:
            prior_job = self.Machines[Machine].assign_for[-1]
            prior_job_info = self.order_data[prior_job[0]]

            priorjobgg = eval(prior_job_info['产品名称'])[3].split('×')[-1]
            if len(jobgg) > 0 and len(priorjobgg) > 0 and jobgg != priorjobgg:
                device_index = Machine_name + '_规格切换'
                if device_index in self.Switch_dicts.keys():
                    gg_ind = self.Switch_dicts[device_index]

            priorjobys = eval(prior_job_info['产品名称'])[1].split('-')[-1]
            priorjobys_lst = [ys for ys in priorjobys if ys in ['红','蓝','绿','黄','黑','白']]
            if len(jobys_lst) > 0 and len(priorjobys_lst) > 0 and ''.join(jobys_lst) != ''.join(priorjobys_lst):
                color_index = Machine_name + '_颜色切换'
                if color_index in self.Switch_dicts.keys():
                    ys_ind = self.Switch_dicts[color_index]
        switch_t = ys_ind + gg_ind
        last_mt = max(self.Machines[Machine].End) if len(self.Machines[Machine].End) > 0 else 0
        last_ot = max(self.Jobs[Job_i[0]].End) if len(self.Jobs[Job_i[0]].End) > 0 else 0
        Start_t = max(last_ot,last_mt)

        if switch_t > 0:
            if ys_ind > 0 and gg_ind > 0:
                obs = '规格颜色切换'
            elif gg_ind == 0:
                obs = '颜色切换'
            else:
                obs = '规格切换'
            self.Machines[Machine]._add_Switch(Start_t, Start_t+switch_t, obs, switch_t)

        Start_time= Start_t + switch_t
        PT=(int(self.order_data[Job_i[0]]['数量'])*100)/float(self.Job_passtime_matrixs[Job_i[0]][Machine,Job_i[1]])
        assert PT > 0
        end_time=Start_time+PT
        self.Machines[Machine]._add(Start_time,end_time,Job_i,PT)
        self.Jobs[Job_i[0]]._add(Start_time,end_time,Machine,PT)
        self._Update(Job_i[0],Machine)




